home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-03-17 | 13.2 KB | 493 lines | [TEXT/CWIE] |
- //
- // CVehicleViewPane.cp
- //
- // The view from the vehicle (a camera and lights) into a QD3D world.
- //
- // By James Jennings
- // Started July 9 1996
- //
-
- #include "CVehicleViewPane.h"
- #include "CGetKeys.h"
- #include "CQTVRCursor.h"
- #include "CColorPicker.h"
-
- const SDimension16 kDefaultSize = { 300, 200 };
- const TQ3Point3D kZero = { 0, 0, 0 };
-
- CVehicleViewPane * CVehicleViewPane::CreateFromStream( LStream *inStream )
- {
- return new CVehicleViewPane( inStream );
- }
-
- CVehicleViewPane::CVehicleViewPane( LStream *inStream )
- : CQD3DPane( inStream ), mVehicle( this ),
- mCenter(kZero), mSceneRadius(0), mLastTime(0)
- {
- // In case kDefaultSize is not the pane's real size.
- AdjustQ3ViewToFrame();
-
- // SetCamera( mVehicle.GetCamera() );
- // SetLights( mVehicle.GetLights() );
- }
-
- void CVehicleViewPane::SetModel( TQ3GroupObject inGroup )
- {
- CQD3DPane::SetModel(inGroup);
-
- // Tell the vehicle the scale of the scene.
- TQ3BoundingBox theBox;
- CalcBoundingBox(theBox);
-
- TQ3Vector3D diagonal;
- ::Q3Point3D_Subtract( &theBox.max, &theBox.min, &diagonal );
- float scale = ::Q3Vector3D_Length(&diagonal);
-
- // Avoid problems with empty scenes.
- if (scale <= kQ3RealZero) scale = 1;
-
- mVehicle.SetScale(scale);
-
- // Remember the center of the scene.
- ::Q3Vector3D_Scale(&diagonal, 0.5, &diagonal);
- ::Q3Point3D_Vector3D_Add(&theBox.min, &diagonal, &mCenter);
- mSceneRadius = scale/2;
-
- StartIdling(); // so that the modifier keys can be read
- }
-
- TQ3CameraObject CVehicleViewPane::GetCamera(void)
- {
- // We store the camera in the vehicle.
- return mVehicle.GetCamera();
-
- // debug
- // return CQD3DPane::GetCamera();
- }
-
- void CVehicleViewPane::SetCamera( TQ3CameraObject inCamera )
- {
- // We store the camera in the vehicle.
- mVehicle.SetCamera(inCamera);
- RebuildView(); // forces the view to be rebuilt
- }
-
- TQ3GroupObject CVehicleViewPane::GetLights(void)
- {
- if ( mLights == nil ) {
- // No lights were supplied. Get the default lights from the vehicle.
-
- // make the headlight group
- TQ3GroupPosition pos;
- mLights = ::Q3LightGroup_New();
- ThrowIfNil_(mLights);
-
- // ambient light (so that our built in models are never totally dark)
- TQ3LightData data;
-
- data.isOn = kQ3True;
- ::Q3ColorRGB_Set(&(data.color), 1.0, 1.0, 1.0); // White Light
- data.brightness = .2;
-
- TQ3LightObject amb = ::Q3AmbientLight_New(&data);
- ThrowIfNil_(amb);
-
- pos = ::Q3Group_AddObject( mLights, amb );
- Q3Forget( amb );
- ThrowIf_(pos==0);
-
- // Add the vehicle headlights
- mVehicle.AddHeadlightsToGroup(mLights);
-
- // add the "extra light": One ambient and one directional.
- pos = ::Q3Group_AddObject( mLights, mExtraLight.Get() );
- ThrowIf_(pos==0);
- pos = ::Q3Group_AddObject( mLights, mExtraLight2.Get() );
- ThrowIf_(pos==0);
- }
-
- return mLights;
- }
-
- void CVehicleViewPane::SetLights( TQ3GroupObject inGroup )
- {
- // Add the vehicle headlights
- mVehicle.AddHeadlightsToGroup(inGroup);
-
- // add the "extra light": One ambient and one directional.
- TQ3GroupPosition pos;
- pos = ::Q3Group_AddObject( inGroup, mExtraLight.Get() );
- ThrowIf_(pos==0);
- pos = ::Q3Group_AddObject( inGroup, mExtraLight2.Get() );
- ThrowIf_(pos==0);
-
- // pass on to superclass
- CQD3DPane::SetLights(inGroup);
- }
-
- void CVehicleViewPane::ClickSelf(const SMouseDownEvent &inMouseDown)
- {
- // Use the mouse to change direction.
- FocusDraw(); // need the correct port to do mouse calculations
-
- Point first = inMouseDown.whereLocal;
-
- // aLittle is the amount to yaw or pitch by, in radians/tick
- const float aLittle = Q3Math_DegreesToRadians( 0.05 );
- const Int16 kMin = 2; // minimum detectable mouse motion
- const Int16 kMax = 72; // maximum effective mouse motion
-
- long t0 = ::TickCount();
-
- while ( StillDown() ) {
-
- // don't do anything until some measurable time has passed.
- float t1 = ::TickCount();
- if (t0 == t1) continue;
-
- // Limit the apparent number of ticks between iterations
- // so things don't get too difficult when the machine can't keep up.
- Int32 t = t1 - t0;
- if (t > 6) t = 6;
-
- // allow accelerations while dragging
- Boolean needsToDraw = CheckAccelerationKeys( false );
-
- Point delta;
- ::GetMouse( &delta );
- ::SubPt( first, &delta );
-
- // Limit the maximum drag.
- if (delta.h > kMax) delta.h = kMax;
- else if (delta.h < -kMax) delta.h = -kMax;
- if (delta.v > kMax) delta.v = kMax;
- else if (delta.v < -kMax) delta.v = -kMax;
- // Eliminate the kMin "dead" space
- if (delta.h > kMin) delta.h -= kMin;
- else if (delta.h < -kMin) delta.h += kMin;
- else delta.h = 0;
- if (delta.v > kMin) delta.v -= kMin;
- else if (delta.v < -kMin) delta.v += kMin;
- else delta.v = 0;
-
- if ( delta.h != 0 || delta.v != 0 ) {
-
- // how much to yaw and pitch by, scaled by time
- float y = - aLittle * delta.h * t;
- float p = - aLittle * delta.v * t;
-
- if ( y != 0 ) {
- mVehicle.YawBy( y );
- needsToDraw = true;
- }
- if ( p != 0 ) {
- mVehicle.PitchBy( p );
- needsToDraw = true;
- }
-
- if (mVehicle.StabilizeRoll()) {
- needsToDraw = true;
- }
-
- // adjust the cursor
- #if 1
- if ( y!=0 || p!=0 ) {
- float k = fabs(p);
- if ( fabs(y) > k ) k = fabs(y);
-
- CQTVRCursor::Set( - y * 256 / k, - p * 256 / k );
- }
- #else
- // This version has trouble seeing non-diagonal cursors for small drags.
- if ( delta.h!=0 || delta.v!=0 ) {
- CQTVRCursor::Set( delta.h, delta.v );
- }
- #endif
-
- } else {
- CQTVRCursor::StopTracking();
- }
-
- if ( needsToDraw )
- Draw(nil);
-
- t0 = t1;
-
- }
-
- }
-
- void CVehicleViewPane::SpendTime( const EventRecord &/*inMacEvent*/ )
- {
- if ( CheckAccelerationKeys( true ) )
- Draw(nil);
- }
-
- void CVehicleViewPane::AdjustCursorSelf(
- Point /* inPortPt */, const EventRecord& /* inMacEvent */)
- {
- CQTVRCursor::NotTracking();
- }
-
- Boolean CVehicleViewPane::CheckAccelerationKeys( Boolean inDraw )
- { // Check the acceleration keys and move accordingly.
- // Return 'true' if we moved.
-
- Boolean moved = false; // the result
-
- if ( !IsTarget() ) // don't read the keys unless we're the target
- return moved;
-
- // don't do anything unless a measurable time has passed
- Int32 t1 = ::TickCount();
- if ( mLastTime == t1 ) return false;
-
- float t = (float)(t1 - mLastTime);
-
- // Note: Reading inMacEvent.modifiers isn't reliable!
- CGetKeys key;
- Boolean shift = key.IsDown(code_Shift);
- Boolean fwd = key.IsDown(code_Option) && !shift;
- Boolean back = key.IsDown(code_Control) && !shift;
- Boolean left = key.IsDown(code_LeftArrow) && !shift;
- Boolean right = key.IsDown(code_RightArrow) && !shift;
- Boolean up = key.IsDown(code_UpArrow) && !shift;
- Boolean down = key.IsDown(code_DownArrow) && !shift;
- Boolean yawLt = key.IsDown(code_LeftArrow) && shift;
- Boolean yawRt = key.IsDown(code_RightArrow) && shift;
- Boolean pitchUp = key.IsDown(code_UpArrow) && shift;
- Boolean pitchDn = key.IsDown(code_DownArrow) && shift;
- Boolean rollRt = key.IsDown(code_Option) && shift;
- Boolean rollLt = key.IsDown(code_Control) && shift;
-
- {
- Int16 signX = ((right)?(1):(0)) - ((left)?(1):(0));
- Int16 signY = ((fwd )?(1):(0)) - ((back)?(1):(0));
- Int16 signZ = ((up )?(1):(0)) - ((down)?(1):(0));
-
- if ( mVehicle.Boost(t, signX, signY, signZ) )
- moved = true;
- }
-
- {
- Int16 signY = ((yawLt )?(1):(0)) - ((yawRt )?(1):(0));
- Int16 signP = ((pitchUp)?(1):(0)) - ((pitchDn)?(1):(0));
- Int16 signR = ((rollRt )?(1):(0)) - ((rollLt )?(1):(0));
-
- if ( mVehicle.Spin(t, signY, signP, signR) )
- moved = true;
- }
-
- mLastTime = t1;
-
- return moved;
- }
-
-
- #pragma mark === Commander Methods ===
-
- Boolean CVehicleViewPane::ObeyCommand(
- CommandT inCommand,
- void *ioParam)
- {
- TQ3Status theStatus;
- Boolean cmdHandled = false;
-
- TQ3CameraPlacement place;
-
- switch ( inCommand ) {
-
- case cmd_LightsOff:
- case cmd_LeftLight:
- case cmd_RightLight:
- case cmd_BothLights:
- case cmd_CenteredLights:
- case cmd_SeparatedLights:
- mVehicle.SetLightMode(inCommand);
- Draw(nil);
- break;
-
- case cmd_ExtraLights:
- Boolean isOn = mExtraLight.IsOn();
- mExtraLight.TurnOn(!isOn);
- mExtraLight2.TurnOn(!isOn);
- Draw(nil);
- break;
-
- case cmd_ViewFromFront: // place on +Z axis
- ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y, mCenter.z + mSceneRadius*2);
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
- ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
- case cmd_ViewFromBack: // place on -Z axis
- ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y, mCenter.z - mSceneRadius*2);
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
- ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
- case cmd_ViewFromLeft: // place on -X axis (audience, not stage, left)
- ::Q3Point3D_Set(&place.cameraLocation, mCenter.x - mSceneRadius*2, mCenter.y, mCenter.z);
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
- ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
- case cmd_ViewFromRight: // place on +X axis
- ::Q3Point3D_Set(&place.cameraLocation, mCenter.x + mSceneRadius*2, mCenter.y, mCenter.z);
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
- ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
- case cmd_ViewFromTop: // place on +Y axis
- ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y + mSceneRadius*2, mCenter.z);
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
- ::Q3Vector3D_Set(&place.upVector, 0, 0, -1);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
- case cmd_ViewFromBottom: // place on -Y axis
- ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y - mSceneRadius*2, mCenter.z);
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
- ::Q3Vector3D_Set(&place.upVector, 0, 0, 1);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
- case cmd_ViewFromCenter: // place at mCenter, looking along Z axis
- ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y, mCenter.z);
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z + mSceneRadius*2);
- ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
-
- case cmd_LookAtCenter: // disable if we are at the center?
- mVehicle.GetPlacement(place);
- // sanity check: Should never fail if we get FindCommandStatus() working.
- float d = ::Q3Point3D_Distance( &place.cameraLocation, &mCenter );
- if ( d < mSceneRadius/1000 ) break;
-
- ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
- mVehicle.SetPlacement(place);
- Refresh();
- break;
-
- case cmd_StabilizeRoll:
- mVehicle.SetRollStabilized(!mVehicle.RollIsStabilized());
- break;
-
- case cmd_BackgroundColor:
- DoBackgroundColor();
- break;
-
- default:
- cmdHandled = LCommander::ObeyCommand( inCommand, ioParam );
- break;
- }
- return cmdHandled;
- }
-
- void CVehicleViewPane::FindCommandStatus(
- CommandT inCommand,
- Boolean &outEnabled,
- Boolean &outUsesMark,
- Char16 &outMark,
- Str255 outName)
- {
- switch ( inCommand ) {
-
- // LDocument turns these on by default. I'll turn them off.
- case cmd_Save:
- case cmd_SaveAs:
- outEnabled = false;
- break;
-
- case cmd_LightsOff:
- case cmd_LeftLight:
- case cmd_RightLight:
- case cmd_BothLights:
- outEnabled = true;
- outUsesMark = true;
- outMark = ((inCommand == mVehicle.GetHeadlightState()) ? (checkMark) : (noMark));
- break;
- case cmd_CenteredLights:
- outEnabled = true;
- outUsesMark = true;
- outMark = ((mVehicle.AreHeadlightsMerged()) ? (checkMark) : (noMark));
- break;
- case cmd_SeparatedLights:
- outEnabled = true;
- outUsesMark = true;
- outMark = ((!mVehicle.AreHeadlightsMerged()) ? (checkMark) : (noMark));
- break;
- case cmd_ExtraLights:
- outEnabled = true;
- outUsesMark = true;
- outMark = ((mExtraLight.IsOn()) ? (checkMark) : (noMark));
- break;
- case cmd_ViewFromFront:
- case cmd_ViewFromBack:
- case cmd_ViewFromLeft:
- case cmd_ViewFromRight:
- case cmd_ViewFromTop:
- case cmd_ViewFromBottom:
- case cmd_ViewFromCenter:
- outEnabled = true;
- break;
-
- case cmd_LookAtCenter: // disable if we are at the center
- #if 0
- // This doesn't get called often enough to be useable.
- // Do we take the overhead of calling SetUpdateCommandStatus()
- // while rendering?
- TQ3CameraPlacement place;
- mVehicle.GetPlacement(place);
- float d = ::Q3Point3D_Distance( &place.cameraLocation, &mCenter );
- outEnabled = ( d > mSceneRadius/1000 );
- #else
- outEnabled = true;
- #endif
- break;
-
- case cmd_StabilizeRoll:
- outEnabled = true;
- outUsesMark = true;
- outMark = ((mVehicle.RollIsStabilized()) ? (checkMark) : (noMark));
- break;
-
- case cmd_BackgroundColor:
- outEnabled = CColorPicker::IsAvailable();
- break;
-
- default:
- LCommander::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
- }
- }
-
- void CVehicleViewPane::DoBackgroundColor()
- {
- // Use the Color Picker to choose a new Clear Image Color.
- TQ3ColorARGB theQ3Color;
- GetClearImageColor(theQ3Color);
-
- RGBColor theQDColor;
- theQDColor.red = theQ3Color.r * 0xFFFF;
- theQDColor.green = theQ3Color.g * 0xFFFF;
- theQDColor.blue = theQ3Color.b * 0xFFFF;
-
- CColorPicker picker;
- if (picker.Choose(theQDColor)) {
-
- theQ3Color.r = (float)theQDColor.red / 0xFFFF;
- theQ3Color.g = (float)theQDColor.green / 0xFFFF;
- theQ3Color.b = (float)theQDColor.blue / 0xFFFF;
- SetClearImageColor(theQ3Color);
-
- Refresh();
- }
-
- }
-